﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

using DragDraw.UserService;
using DragDraw.Util;

namespace DragDraw.Tool
{
    public partial class DrawBoard : UserControl
    {
        private bool m_isMouseDown;
        private Point m_mouseOldPoint;
        private Point m_mouseCurPoint;
        private DrawBoardStatus m_status = DrawBoardStatus.Line;
        private FrameworkElement m_curElem;

        WidgetServiceProxy m_service;
        bool m_joined = false;

        public DrawBoard()
        {
            InitializeComponent();
            BtnLine_Click(null, null);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (!m_joined)
            {
                m_service = OperationManager.Instance.CreateWidgetServiceProxy(this);
                m_service.OnDuplexSessionUpdate += OnReceive;

                m_service.JoinDuplexSession("drawing");
                m_joined = true;
            }
        }

        void OnReceive(object sender, OnUpdateSessionEventArgs e)
        {
            //ErrorManager.Instance.ShowDebugMessage("on recv");
            XmlSerializer xs = new XmlSerializer(typeof(DrawBoardDesc));
            DrawBoardDesc desc = (DrawBoardDesc)xs.Deserialize(new StringReader(e.Result.Value));
            HandleRecieveDesc(desc);
        }

        private void HandleRecieveDesc(DrawBoardDesc desc)
        {
            switch (desc.ElemType)
            {
                case "line":
                    DrawLine(desc.Points[0].X, desc.Points[0].Y,
                        desc.Points[1].X, desc.Points[1].Y);
                    break;
                case "rect":
                    DrawRect(desc.Points[0].X, desc.Points[0].Y,
                         desc.Points[1].X - desc.Points[0].X,
                         desc.Points[1].Y - desc.Points[0].Y);
                    break;
                case "text":
                    DrawText(desc.Points[0].X, desc.Points[0].Y, desc.Text);
                    break;
                case "clear":
                    DrawRoot.Children.Clear();
                    break;
            }
        }

        private void DrawLine(double x1, double y1, double x2, double y2)
        {
            Line l = new Line();
            l.Stroke = new SolidColorBrush(Color.FromArgb(0xff, 0x00, 0x00, 0x00));
            l.StrokeThickness = 2;
            l.X1 = x1;
            l.Y1 = y1;
            l.X2 = x2;
            l.Y2 = y2;
            DrawRoot.Children.Add(l);
        }

        private void DrawRect(double left, double top, double width, double height)
        {
            Rectangle r = new Rectangle();
            r.Stroke = new SolidColorBrush(Color.FromArgb(0xff, 0x00, 0x00, 0x00));
            r.StrokeThickness = 2;
            r.SetValue(Canvas.TopProperty, top);
            r.SetValue(Canvas.LeftProperty, left);
            r.Height = height;
            r.Width = width;
            DrawRoot.Children.Add(r);
        }

        private void DrawText(double left, double top, string text)
        {
            TextBlock tb = new TextBlock();
            tb.FontSize = 13;
            tb.Text = text;
            tb.SetValue(Canvas.TopProperty, top);
            tb.SetValue(Canvas.LeftProperty, left);
            DrawRoot.Children.Add(tb);
        }

        private void DrawRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            m_isMouseDown = true;

            m_mouseOldPoint = e.GetPosition(DrawRoot);
            m_mouseCurPoint = e.GetPosition(DrawRoot);

            FrameworkElement element = sender as FrameworkElement;
            if (element != null)
                element.CaptureMouse();
            /*
            DrawBoardDesc desc = new DrawBoardDesc();
            switch (m_status)
            {
                case DrawBoardStatus.Line:
                    break;
                case DrawBoardStatus.Text:
                    TextBox tb = new TextBox();
                    DrawRoot.Children.Add(tb);
                    m_curElem = tb;
                    break;
                case DrawBoardStatus.Rect:
                    break;
                case DrawBoardStatus.Delete:
                    break;
                default:
                    ErrorManager.Instance.ShowDebugMessage("DrawBoardStatus Error!");
                    break;
            }*/
        }

        private void DrawRoot_MouseMove(object sender, MouseEventArgs e)
        {
            if (!m_isMouseDown) return;

            m_mouseCurPoint = e.GetPosition(DrawRoot);
        }

        private void DrawRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //ErrorManager.Instance.ShowDebugMessage("mouse up");
            m_isMouseDown = false;

            m_mouseCurPoint = e.GetPosition(DrawRoot);

            FrameworkElement element = sender as FrameworkElement;
            element.ReleaseMouseCapture();

            switch (m_status)
            {
                case DrawBoardStatus.Text:
                    SendText(m_mouseCurPoint.X, m_mouseCurPoint.Y, TxtNew.Text);
                    break;
                case DrawBoardStatus.Line:
                    SendLine(m_mouseOldPoint.X, m_mouseOldPoint.Y,
                        m_mouseCurPoint.X, m_mouseCurPoint.Y);
                    break;
                case DrawBoardStatus.Rect:
                    double top, left, height, width;
                    if (m_mouseCurPoint.X < m_mouseOldPoint.X)
                    {
                        left = m_mouseCurPoint.X;
                        width = m_mouseOldPoint.X - m_mouseCurPoint.X;
                    }
                    else
                    {
                        left = m_mouseOldPoint.X;
                        width = m_mouseCurPoint.X - m_mouseOldPoint.X;
                    }
                    if (m_mouseCurPoint.Y < m_mouseOldPoint.Y)
                    {
                        top = m_mouseCurPoint.Y;
                        height = m_mouseOldPoint.Y - m_mouseCurPoint.Y;
                    }
                    else
                    {
                        top = m_mouseOldPoint.Y;
                        height = m_mouseCurPoint.Y - m_mouseOldPoint.Y;
                    }
                    SendRect(left, top, width, height);
                    break;
                case DrawBoardStatus.Delete:
                    break;
                default:
                    ErrorManager.Instance.ShowDebugMessage("DrawBoardStatus Error!");
                    break;
            }
        }

        private void SendLine(double x1, double y1, double x2, double y2)
        {
            DrawBoardDesc desc = new DrawBoardDesc();
            desc.ElemType = "line";
            desc.Points.Add(new Point(x1, y1));
            desc.Points.Add(new Point(x2, y2));
            SendDesc(desc);
        }

        private void SendRect(double left, double top, double width, double height)
        {
            DrawBoardDesc desc = new DrawBoardDesc();
            desc.ElemType = "rect";
            desc.Points.Add(new Point(left, top));
            desc.Points.Add(new Point(left + width, top + height));
            SendDesc(desc);
        }

        private void SendText(double left, double top, string text)
        {
            DrawBoardDesc desc = new DrawBoardDesc();
            desc.ElemType = "text";
            desc.Points.Add(new Point(left, top));
            desc.Text = text;
            SendDesc(desc);
        }

        private void SendClear()
        {
            DrawBoardDesc desc = new DrawBoardDesc();
            desc.ElemType = "clear";
            SendDesc(desc);
        }

        private void SendDesc(DrawBoardDesc desc)
        {
            XmlSerializer xs = new XmlSerializer(typeof(DrawBoardDesc));
            StringWriter sw = new StringWriter();
            xs.Serialize(sw, desc);
            m_service.UpdateDuplexSession("drawing", sw.ToString());
        }

        private void BtnLine_Click(object sender, RoutedEventArgs e)
        {
            m_status = DrawBoardStatus.Line;
            TextPanel.Visibility = Visibility.Collapsed;
            TxtNew.Text = "";
        }

        private void BtnText_Click(object sender, RoutedEventArgs e)
        {
            m_status = DrawBoardStatus.Text;
            TextPanel.Visibility = Visibility.Visible;
        }

        private void BtnRect_Click(object sender, RoutedEventArgs e)
        {
            m_status = DrawBoardStatus.Rect;
            TextPanel.Visibility = Visibility.Collapsed;
        }

        private void BtnDelete_Click(object sender, RoutedEventArgs e)
        {
            m_status = DrawBoardStatus.Delete;
            TextPanel.Visibility = Visibility.Collapsed;
            SendClear();
        }
    }

    public class DrawBoardDesc
    {
        public string ElemType { get; set; }//"line", "text", "rect"
        public List<Point> Points { get; set; }
        public string Text { get; set; }
        public DrawBoardDesc()
        {
            ElemType = "";
            Points = new List<Point>();
            Text = "";
        }
    }

    public enum DrawBoardStatus
    {
        Arrow,
        Text,
        Line,
        Rect,
        Delete
    }
}
